﻿namespace JoinBox.Basal;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Threading;


public class PingPingPing
{
    public const string _SharedFoldersA = "中转站";
    public const string _SharedFolders = @"\" + _SharedFoldersA;

    /// <summary>
    /// 网段
    /// </summary>
    public string NetworkSegment = "192.168.1";

    /// <summary>
    /// 按了第几次ping,直到关闭才重置
    /// </summary>
    public int pingEnt = 0;
    /// <summary>
    /// 启用ping的时候计数,直到关闭才重置
    /// </summary>
    public int qiyongEnt = 0;
    public bool WaitOne = true;
    public int ipNumber = 256;                           // ip数
    public List<HostInformation> ComputerNames = new();  // 记录电脑名称和对应的ip,必须初始化,不然无法lock
    public AutoResetEvent pingOver;                      // 线程池结束标记


    public PingPingPing()
    {
        WaitOne       = true;
        ipNumber      = 256;                      // ip数
        pingOver      = new AutoResetEvent(false);// 线程池结束标记
        ComputerNames = new List<HostInformation>();
    }

    public void PingIP(object? obj)
    {
        // 0是ip,1是启动点击的位置
        if (obj is not int[] ints)
            return;
        string ip = NetworkSegment + "." + ints[0].ToString();
        try
        {
            using Ping myPing = new();
            var reply = myPing.Send(ip, 1);
            if (reply.Status.Equals(IPStatus.Success))// ping通了
            {
                string hostname = "";
                // 通过ip获取电脑名称,没有电脑名称会引起错误,造成下面无法递减,必须容错
                hostname = Dns.GetHostEntry(ip).HostName;
                // 当前计数和启用计数要一样才加入,启用是传值的,也是固定的,
                // 而pingEnt是按了按钮就会改的,存在时间差,造成可以判断.
                if (pingEnt == ints[1])
                {
                    if (hostname is not null && hostname.Trim() != "")
                    {
                        var strs = Intranet.GetNetShareList(hostname);
                        if (strs is null || strs.Length == 0)
                        {
                            // 名称和ip在win10通过空密码时候验证不一样..
                            // 所以两个都测试一下(如果空密码没有进入过,都会失败
                            strs = Intranet.GetNetShareList(ip);
                        }
                        if (strs is null || strs.Length == 0)
                            return;

                        lock (ComputerNames)
                        {
                            if (strs.Contains(_SharedFoldersA))
                                ComputerNames.Add(new HostInformation(hostname.ToUpper(), ip, "有:" + _SharedFoldersA));
                            else
                                ComputerNames.Add(new HostInformation(hostname.ToUpper(), ip, "有共享文件夹,无:" + _SharedFoldersA));
                        }
                    }
                    else
                    {
                        lock (ComputerNames)
                        {
                            ComputerNames.Add(new HostInformation(ip, ip, "没有机名但是ping通了"));
                        }
                    }
                }
            }
        }
        catch
        { }
        // 上面必须容错,实行这里的递减
        // 线程池计数,用来实现最后一个线程时候通知.
        ipNumber--;
        // Thread.Sleep(500);
        if (ipNumber == 0)
            pingOver.Set();
    }

    /// <summary>
    /// 一直等待到找到或者结束
    /// </summary>
    /// <param name="pcname"></param>
    /// <returns></returns>
    public string? WhilePing(string? pcname)
    {
        if (pcname is null)
            throw new ArgumentException(nameof(pcname));

        pcname = pcname.ToUpper();
        string? ip = null;
        try
        {
            while (true)
            {
                foreach (var item in ComputerNames.ToArray())// 防止线程更改了list,必须toarray
                {
                    if (item.HostName == pcname)
                    {
                        ip = item.HostIP; // 如果找到了ip,就拿出来
                        break;
                    }
                }
                if (WaitOne) // 等待过一次就不能再用这个函数
                {
                    WaitOne = false;
                    pingOver.WaitOne();// 等待 pingOver.Set();执行,表示线程池已经终止,如果线程结束,重复等待就会死掉了
                }
                else
                {
                    break;
                }
            }
        }
        catch
        { }
        return ip;
    }
}


public class HostInformation
{
    public string HostName;
    public string HostIP;
    public string Remarks;
    public HostInformation(string hostname, string hostip, string remarks)
    {
        HostName = hostname;
        HostIP   = hostip;
        Remarks  = remarks;
    }
}